﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using UtilPublic.Serialization;

namespace UtilPublic
{
    /// <summary>
    /// 
    /// </summary>
    public class PropertiesNode
    {
        /// <summary>
        /// 
        /// </summary>
        public string Label { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Desc { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public object Value { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="label"></param>
        /// <param name="desc"></param>
        /// <param name="value"></param>
        public PropertiesNode(string label, string desc, object value)
        {
            Label = label;
            Desc = desc;
            Value = value;
        }
    }
    /// <summary>
    /// 属性字符串
    /// </summary>
    [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property)]
    public class DescAttribute : Attribute
    {
        /// <summary>
        /// 
        /// </summary>
        public string DescStr { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="v"></param>
        public DescAttribute(string v) { DescStr = v; }
    }
    /// <summary>
    /// 管理器
    /// </summary>
    public static class DescManager
    {
        private static Dictionary<Type, List<string>> CacheListProperties = new Dictionary<Type, List<string>>();
        private static Dictionary<Type, List<string>> CacheListDesc = new Dictionary<Type, List<string>>();
        private static Dictionary<Type, Dictionary<string, string>> CachePropertiesDesc = new Dictionary<Type, Dictionary<string, string>>();
        private static Dictionary<Type, Dictionary<string, string>> CacheDescProperties = new Dictionary<Type, Dictionary<string, string>>();
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<string> GetListProperties(Type type)
        {
            if (!CacheListProperties.ContainsKey(type))
            {
                Cache(type);
            }
            try
            {
                return CacheListProperties[type];
            }
            catch
            {
                return new List<string>();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<string> GetListDesc(Type type)
        {
            if (!CacheListDesc.ContainsKey(type))
            {
                Cache(type);
            }
            try
            {
                return CacheListDesc[type];
            }
            catch
            {
                return new List<string>();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static string GetDescByProperties(object p)
        {
            var type = p.GetType();
            if (!CachePropertiesDesc.ContainsKey(type))
            {
                Cache(type);
            }
            var fieldName = p.ToString();
            try
            {
                return CachePropertiesDesc[type][fieldName];
            }
            catch
            {
                return $"Can not found such Desc for field `{fieldName}` in type `{type.Name}`";
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string GetDescByName(Type type, string name)
        {
            if (!CachePropertiesDesc.ContainsKey(type))
            {
                Cache(type);
            }
            try
            {
                return CachePropertiesDesc[type][name];
            }
            catch
            {
                return name;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="desc"></param>
        /// <returns></returns>
        public static string GetNameByDesc(Type type, string desc)
        {
            if (!CacheDescProperties.ContainsKey(type))
            {
                Cache(type);
            }
            try
            {
                return CacheDescProperties[type][desc];
            }
            catch
            {
                return desc;
            }
        }

        private static void Cache(Type type)
        {
            var list1 = new List<string>();
            var list2 = new List<string>();
            var dict1 = new Dictionary<string, string>();
            var dict2 = new Dictionary<string, string>();
            CacheListProperties.Add(type, list1);
            CacheListDesc.Add(type, list2);
            CachePropertiesDesc.Add(type, dict1);
            CacheDescProperties.Add(type, dict2);
            var fields = type.GetFields();
            foreach (var field in fields)
            {
                var objs = field.GetCustomAttributes(typeof(DescAttribute), true);
                if (objs.Length > 0)
                {
                    list1.Add(field.Name);
                    list2.Add(((DescAttribute)objs[0]).DescStr);
                    dict1[field.Name] = ((DescAttribute)objs[0]).DescStr;
                    dict2[((DescAttribute)objs[0]).DescStr] = field.Name;
                }
            }
        }

        /// <summary>
        /// 输出此类的所有属性名和属性对应的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="strSeparator1"></param>
        /// <returns></returns>
        public static string GetProperty<T>(T t, string strSeparator1 = "\r\n")
        {
            var sb = new StringBuilder();
            if (t == null)
            {
                return "";
            }
            var propertys = t.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var item in propertys)
            {
                object value = item.GetValue(t, null);
                if (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String"))
                {
                    sb.Append($"{item.Name}----->{value}{strSeparator1}");
                }
                else
                {
                    GetProperty(value);
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// 输出此类的所有属性名和属性对应的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="strSeparator1"></param>
        /// <returns></returns>
        public static string GetFields<T>(T t, string strSeparator1 = "\r\n")
        {
            var sb = new StringBuilder();
            if (t == null)
            {
                return "";
            }
            var fields = t.GetType().GetFields();
            foreach (var item in fields)
            {
                object value = item.GetValue(t);
                if (item.FieldType.IsValueType || item.FieldType.Name.StartsWith("String"))
                {
                    sb.Append($"{item.Name}----->{item.GetValue(t)}{strSeparator1}");
                }
                else
                {
                    GetFields(value);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 输出此类的所有属性名和属性对应的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="strSeparator1"></param>
        /// <returns></returns>
        public static string GetPropertyDesc<T>(T t, string strSeparator1 = "\r\n")
        {
            var sb = new StringBuilder();
            if (t == null)
            {
                return "";
            }
            var propertys = t.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var item in propertys)
            {
                object value = item.GetValue(t, null);
                var objs = item.GetCustomAttributes(typeof(DescAttribute), true);
                if (objs.Length > 0)
                {
                    if (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String"))
                    {
                        sb.Append($"{((DescAttribute)objs[0]).DescStr}({item.Name})----->{value}{strSeparator1}");
                    }
                    else
                    {
                        GetPropertyDesc(value);
                    }
                }
            }
            return sb.ToString();
        }
        /// <summary>
        /// 输出此类的所有属性名和属性对应的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="strSeparator1"></param>
        /// <returns></returns>
        public static string GetFieldsDesc<T>(T t, string strSeparator1 = "\r\n")
        {
            var sb = new StringBuilder();
            if (t == null)
            {
                return "";
            }
            var fields = t.GetType().GetFields();
            foreach (var item in fields)
            {
                object value = item.GetValue(t);
                var objs = item.GetCustomAttributes(typeof(DescAttribute), true);
                if (objs.Length > 0)
                {
                    if (item.FieldType.IsValueType || item.FieldType.Name.StartsWith("String"))
                    {
                        sb.Append($"{item.Name,-30}{item.GetValue(t),-20}{((DescAttribute)objs[0]).DescStr}{strSeparator1}");
                    }
                    else if (item.FieldType.IsGenericType && item.FieldType.Name.StartsWith("List`1"))
                    {
                        //int count = Convert.ToInt32(item.FieldType.GetProperty("Count").GetValue(value, null));
                        //var listItem = new List<object>();
                        //for (int i = 0; i < count; i++)
                        //{
                        //    object o = item.FieldType.GetProperty("Item").GetValue(value, new object[] { i });
                        //    listItem.Add(o);
                        //}
                        //sb.Append($"{item.Name,-30}{Util.ToStr(listItem)}{$" <{((DescAttribute)objs[0]).DescStr}>"}{strSeparator1}");

                        sb.Append($"{item.Name}({((DescAttribute)objs[0]).DescStr}):\r\n{Jsh.Jstr(value)}{strSeparator1}");
                    }
                    else if (item.FieldType.IsGenericType && (item.FieldType.Name.StartsWith("Dictionary`2") || item.FieldType.Name.StartsWith("SortedDictionary`2")))
                    {
                        //var o1 = item.FieldType.GetProperty("Keys").GetValue(value, null) as IEnumerable;
                        //var o2 = item.FieldType.GetProperty("Values").GetValue(value, null) as IEnumerable;
                        //var listItem = new Dictionary<object, object>();
                        //var listItem1 = new List<object>();
                        //var listItem2 = new List<object>();
                        //foreach (object ooo in o1)
                        //{
                        //    listItem1.Add(ooo);
                        //}
                        //if (item.FieldType.GetGenericArguments()[1].Name == "String"
                        //    || item.FieldType.GetGenericArguments()[1].Name == "Int32"
                        //    || item.FieldType.GetGenericArguments()[1].Name == "Int64"
                        //    || item.FieldType.GetGenericArguments()[1].Name == "Single")
                        //{
                        //    foreach (object ooo in o2)
                        //    {
                        //        listItem2.Add(ooo);
                        //    }
                        //}
                        //else
                        //{
                        //    foreach (object ooo in o2)
                        //    {
                        //        listItem2.Add(GetFieldsDesc(ooo));
                        //    }
                        //}
                        //for (int i = 0; i < listItem1.Count; i++)
                        //{
                        //    listItem.Add(listItem1[i], listItem2[i]);
                        //}
                        //sb.Append($"{item.Name,-30}{Util.ToStr(listItem)}{$" <{((DescAttribute)objs[0]).DescStr}>"}{strSeparator1}");

                        sb.Append($"{item.Name}({((DescAttribute)objs[0]).DescStr}):\r\n{Jsh.Jstr(value)}{strSeparator1}");
                    }
                    else
                    {
                        GetFieldsDesc(value, strSeparator1);
                    }
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 输出此类的所有属性名和属性对应的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="result"></param>
        public static void GetFieldsDescList<T>(T t, out List<PropertiesNode> result)
        {
            result = new List<PropertiesNode>();
            if (t == null)
            {
                return;
            }
            var fields = t.GetType().GetFields();
            foreach (var item in fields)
            {
                object value = item.GetValue(t);
                var objs = item.GetCustomAttributes(typeof(DescAttribute), true);
                if (objs.Length > 0)
                {
                    if (item.FieldType.IsValueType || item.FieldType.Name.StartsWith("String"))
                    {
                        result.Add(new PropertiesNode(item.Name, ((DescAttribute)objs[0]).DescStr, item.GetValue(t)));
                    }
                    else
                    {
                        value = GetFieldsDesc(value);
                        result.Add(new PropertiesNode(item.Name, ((DescAttribute)objs[0]).DescStr, value));
                    }
                }
            }
        }




    }

}
